import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { gui } from '../gui'
import { stats } from '../stats'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

function createCourse10 (dom: HTMLElement) {
  const scene = new THREE.Scene()
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)

  const render = new THREE.WebGLRenderer()
  render.setClearColor(new THREE.Color(0x000000))
  render.setSize(window.innerWidth, window.innerHeight)
  render.shadowMap.enabled = true

  dom.appendChild(render.domElement)

  // show axes in the screen
  const axes = new THREE.AxesHelper(50)
  scene.add(axes)

  loadModel()

  const planeGeometry = new THREE.PlaneGeometry(100, 100)
  const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xAAAAAA })
  const plane = new THREE.Mesh(planeGeometry, planeMaterial)

  plane.rotation.x = -0.5 * Math.PI
  plane.position.set(15, 0, 0)
  plane.receiveShadow = true

  scene.add(plane)

  camera.position.x = -5
  camera.position.y = 5
  camera.position.z = 5
  camera.lookAt(scene.position)
  scene.add(camera)

  const spotLight = new THREE.SpotLight(0xFFFFFF)
  spotLight.position.set(-60, 30, -65)
  spotLight.castShadow = true
  spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024)
  spotLight.shadow.camera.far = 130
  spotLight.shadow.camera.near = 40
  // scene.add(spotLight);

  // const ambienLight = new THREE.AmbientLight(0xcccccc)
  // scene.add(ambienLight);

  const pointLight = new THREE.PointLight(0xffffff, 6, 60)
  pointLight.position.set(0, 0, 2)
  scene.add(pointLight)

  const sphereGeo = new THREE.SphereGeometry(0.1)
  const sphereMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 })
  const sphereMesh = new THREE.Mesh(sphereGeo, sphereMaterial)
  sphereMesh.castShadow = true
  sphereMesh.position.copy(pointLight.position)
  scene.add(sphereMesh)

  const ctrlObj = {
    pointColor: 0xffffff,
    pointIntensity: 6,
    pointDistance: 60,
    pointdecay: 1,
    dirColor: 0xffffff,
    dirIntensity: 4,
    pointLightVisible: true,
    dirLightVisible: true
  }

  const ctrl = gui
  const pointLightFolder = ctrl.addFolder('pointLight')
  pointLightFolder.addColor(ctrlObj, 'pointColor').onChange(function (e: number) {
    pointLight.color = new THREE.Color(e)
  })

  pointLightFolder.add(ctrlObj, 'pointIntensity', 0, 10).onChange(function (e: number) {
    pointLight.intensity = e
  })

  pointLightFolder.add(ctrlObj, 'pointDistance', 0, 1000).onChange(function (e: number) {
    pointLight.distance = e
  })

  pointLightFolder.add(ctrlObj, 'pointdecay', 0, 100).onChange(function (e: number) {
    pointLight.decay = e
  })

  pointLightFolder.add(ctrlObj, 'pointLightVisible').onChange(function (e: boolean) {
    pointLight.visible = e
    sphereMesh.visible = e
  })

  const directionalLight = new THREE.DirectionalLight(0xffffff, 4)
  directionalLight.castShadow = true
  directionalLight.shadow.mapSize.width = 2048
  directionalLight.shadow.mapSize.height = 2048
  directionalLight.position.set(20, 20, 20)
  scene.add(directionalLight)

  // const helper = new THREE.DirectionalLightHelper(directionalLight, 5)
  // scene.add(helper);

  // const dirCameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera)
  // scene.add(dirCameraHelper);

  const controls = new OrbitControls(camera, render.domElement)
  controls.update()

  const dirLightFolder = ctrl.addFolder('directionalLight')
  dirLightFolder.addColor(ctrlObj, 'dirColor').onChange(function (e: number) {
    directionalLight.color = new THREE.Color(e)
  })

  dirLightFolder.add(ctrlObj, 'dirIntensity', 0, 10).onChange(function (e: number) {
    directionalLight.intensity = e
  })

  dirLightFolder.add(ctrlObj, 'dirLightVisible').onChange(function (e: boolean) {
    directionalLight.visible = e
  })

  const geometry = new THREE.BoxGeometry(1, 1, 1)
  const material = new THREE.MeshLambertMaterial({ color: 0xff2288 })
  const cube = new THREE.Mesh(geometry, material)
  cube.castShadow = true
  cube.position.set(-20, 2, 0)
  scene.add(cube)
  // directionalLight.target = cube;

  render.setAnimationLoop(animation)

  let pos = 0
  function animation () {
    stats.update()

    pos += 0.1
    pointLight.position.y = Math.abs(Math.sin(pos) * 2)
    sphereMesh.position.copy(pointLight.position)

    controls.update()
    render.render(scene, camera)
  }

  function loadModel () {
    const url = 'https://dongli-three.oss-cn-shanghai.aliyuncs.com/untitled.glb'
    new GLTFLoader()
      .load(url, function (gltf) {
        gltf.scene.scale.set(0.01, 0.01, 0.01)
        gltf.scene.traverse(function (object) {
          if (object.type === 'Mesh') { object.castShadow = true }
        })

        scene.add(gltf.scene)
      })
  }

  return { camera, render, scene }
}

export {
  createCourse10
}
